package jedis;

import com.alibaba.fastjson.JSON;
import com.coderknock.jedis.PubSub;
import com.coderknock.jedis.executor.JedisExecutor;
import jodd.io.FileUtil;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import redis.clients.jedis.*;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * <p></p>
 *
 * @author 三产
 * @version 1.0
 * @date 2017-08-07
 * @QQGroup 213732117 【购买了讲座的童鞋请加 660767582 验证信息输入 sf 用户名】
 * @website http://www.coderknock.com
 * @copyright Copyright 2017 拿客 coderknock.com  All rights reserved.
 * @since JDK 1.8
 */
@DisplayName("Jedis测试")
public class Demo {
    @DisplayName("普通连接方式")
    @ParameterizedTest(name = "参数{index} ==> key=''{0}'', value={1}")
    //@CsvSource({"hello, world", "bar, 2", "'baz, qux', 3"})
    @CsvFileSource(resources = "/connetcionTest.csv")
    public void connection(String key, String value) {
        //1. 生成一个Jedis对象，这个对象负责和指定Redis实例进行通信
        Jedis jedis = null;
        try {
            jedis = new Jedis("127.0.0.1", 6379);
            // host：Redis实例的所在机器的IP。
            // port：Redis实例的端口。
            // connectionTimeout：客户端连接超时。
            // soTimeout：客户端读写超时。
            // 如果 Redis 设置了密码需要进行密码验证
            jedis.auth("admin123");
            //2. jedis执行set操作
            System.out.println(jedis.set(key, value));
            //3. jedis执行get操作
            String getValue = jedis.get(key);
            assertEquals(value, getValue);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //4.使用完毕自动释放资源
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    @DisplayName("连接池连接方式")
    @ParameterizedTest(name = "第{index}组参数 ==> key=''{0}'', listStr={1},getKey{2}  {3}//没有这个索引的参数所以当做字符串输出  arguments ==>{arguments}")
    //@CsvSource({"helloList, world-1243-sfda-re2e-erwsdcv", "barList, 2sdf-ewrqer-fsdcv-sdfs-sdfs", "bazList, qux-ewrqw-r3wer-2413r"})
    @CsvFileSource(resources = "/poolTest.csv")
    public void poolTest(String key, String listStr, String getKey) {
        String[] list = listStr.split("-");
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 1000, "admin123");
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            Pipeline pipeline = jedis.pipelined();
            pipeline.sadd(key, list);
            pipeline.get(getKey);
            System.out.println(JSON.toJSONString(pipeline.syncAndReturnAll()));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            if (jedisPool != null) {
                jedisPool.close();
            }
        }
    }

    @DisplayName("JedisExecutor 使用")
    @Test
    public void JedisExecutorTest() {
        Set<Tuple> result = JedisExecutor.execute(jedis -> {
            jedis.del("tour");
            jedis.geoadd("tour", 123, 23, "test");
            return jedis.zrangeWithScores("tour", 0, -1);
        });
        assertTrue(!result.isEmpty());
        result.forEach(System.out::println);
    }

    @DisplayName("HyperLogLogTest 使用")
    @Test
    public void HyperLogLogTest() {
        String hyperLogLogKey = "HyperLogLogTest";
        String[] ips = getHyperLogLogArray();
        Set<String> ipsSet = new HashSet(Arrays.asList(ips));
        Long result = JedisExecutor.execute(jedis -> {
            if (!jedis.exists(hyperLogLogKey)) {
                jedis.pfadd(hyperLogLogKey, ips);
            }
            return jedis.pfcount(hyperLogLogKey);
        });
        assertEquals(result, Long.valueOf(ipsSet.size()));
        System.out.println(result);
        System.out.println(ipsSet.size());
    }

    @DisplayName("HyperLogLog 与 集合内存性能对比")
    @Test
    public void HyperLogLogSet() {
        String hyperLogLogKey = "HyperLogLogTest";
        String setKey = "SetTest";
        //先将 key 删除掉
        JedisExecutor.executeNR(jedis -> {
            if (jedis.exists(hyperLogLogKey)) {
                long startTime = System.currentTimeMillis();
                jedis.del(hyperLogLogKey);
                System.out.println("del hyperLogLogKey 费时" + (System.currentTimeMillis() - startTime));
            }
            if (jedis.exists(setKey)) {
                long startTime = System.currentTimeMillis();
                jedis.del(setKey);
                System.out.println("del setKey 费时" + (System.currentTimeMillis() - startTime));
            }
        });
        String[] ips = getHyperLogLogArray();
        Set<String> ipsSet = new HashSet(Arrays.asList(ips));
        System.out.println("ipSet 长度" + ipsSet.size());
        long startTime = System.currentTimeMillis();
        Long result = JedisExecutor.execute(jedis -> {
            if (!jedis.exists(setKey)) {
                jedis.sadd(setKey, ips);
            }
            return jedis.scard(setKey);
        });
        System.out.println("集合费时 " + (System.currentTimeMillis() - startTime));
        assertEquals(result, Long.valueOf(ipsSet.size()));
        System.out.println("集合返回结果" + result);
        startTime = System.currentTimeMillis();
        result = JedisExecutor.execute(jedis -> {
            if (!jedis.exists(hyperLogLogKey)) {
                jedis.pfadd(hyperLogLogKey, ips);
            }
            return jedis.pfcount(hyperLogLogKey);
        });
        System.out.println("HyperLogLog 费时 " + (System.currentTimeMillis() - startTime));
        //assertEquals(result, Long.valueOf(ipsSet.size()));
        System.out.println("HyperLogLog 返回结果" + result);

    }

    //127.0.0.1:6379> MEMORY USAGE HyperLogLogTest
    //        (integer) 12359
    //        127.0.0.1:6379> MEMORY USAGE SetTest
    //        (integer) 586753
    //        127.0.0.1:6379> MEMORY USAGE HyperLogLogTest
    //        (integer) 12359
    //        127.0.0.1:6379> MEMORY USAGE SetTest
    //        (integer) 47783985
    private String[] getHyperLogLogArray() {
        String[] ips = new String[1000000];
        Random random = new Random();
        for (int i = 0; i < ips.length; i++) {
            ips[i] = random.nextInt(255) + "." + random.nextInt(255) + "." + random.nextInt(255) + "." + random.nextInt(255);
        }
        return ips;
    }

    @DisplayName("批量插入与单个插入效率对比")
    @Test
    public void lpushLpushAll() {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {
            list.add("val" + i);
        }
        System.out.println("list 长度" + list.size());
        long startTime = System.currentTimeMillis();
        String liseKey = "testList";
        String liseAllKey = "liseAllKey";
        JedisExecutor.executeNR(jedis -> {
            if (jedis.exists(liseKey)) {
                jedis.del(liseKey);
            }
            list.forEach(a -> jedis.lpush(liseKey, a));
        });
        System.out.println("逐个插入费时 " + (System.currentTimeMillis() - startTime));
        JedisExecutor.executeNR(jedis -> System.out.println(jedis.llen(liseKey)));
        startTime = System.currentTimeMillis();
        JedisExecutor.executeNR(jedis -> {
            if (jedis.exists(liseAllKey)) {
                jedis.del(liseAllKey);
            }

            jedis.lpush(liseAllKey, list.toArray(new String[]{}));
        });
        System.out.println("一起插入费时 " + (System.currentTimeMillis() - startTime));
        JedisExecutor.executeNR(jedis -> System.out.println(jedis.llen(liseAllKey)));
    }

    @DisplayName("BitMaps效率")
    @Test
    public void bitMaps() {
        long startTime = System.currentTimeMillis();
        long result = JedisExecutor.execute(jedis -> jedis.bitcount("tag:1"));
        System.out.println("查询单个标签的用户数结果 " + result);
        System.out.println("查询单个标签的用户数耗时 " + (System.currentTimeMillis() - startTime));
        startTime = System.currentTimeMillis();
        result = JedisExecutor.execute(jedis -> {
            String destKey = "tag:1,2,3:and";
            if (jedis.exists(destKey)) {
                jedis.del(destKey);
            }
            jedis.bitop(BitOP.AND, destKey, "tag:1", "tag:2", "tag:3");
            return jedis.bitcount(destKey);
        });
        System.out.println("查询三个标签的用户数结果 " + result);
        System.out.println("查询三个标签的用户数耗时 " + (System.currentTimeMillis() - startTime));
    }

    @DisplayName("Lua 脚本的使用")
    @Test
    public void lua() throws IOException {
        //模拟100长度列表
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(String.valueOf(i));
        }
        String key = "intList";
        JedisExecutor.executeNR((Jedis jedis) -> {
            if (jedis.exists(key)) {
                jedis.del(key);
            }
            jedis.lpush(key, list.toArray(new String[]{}));
        });
        // 将文件中内容读取到字符串中
        String script = FileUtil.readString("E:\\IdeaXGuide\\learn_redis_0820\\src\\test\\java\\jedis\\listFilter.lua");
        JedisExecutor.executeNR(jedis -> System.out.println(jedis.eval(script, 1, key, "88")));
    }

    @DisplayName("Redis 发布订阅")
    @Test
    public void sub() throws IOException, InterruptedException {
        PubSub pubSub = new PubSub();
        JedisExecutor.executeNR((Jedis jedis) -> new Thread(() -> jedis.subscribe(pubSub, "coderknock", "sf")).start());
        TimeUnit.SECONDS.sleep(10);
        pubSub.unsubscribe();
        TimeUnit.SECONDS.sleep(100);
        System.out.println("执行到");
    }
}
